<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    /**
 * Created by jialin on 2016/10/21.
 */
(function (window) {
    var r = {};
    /**
     * 牌型定义：
     *      1.单张
     *      2.对子
     *      3.三张相同
     *      4.三带一
     *      5.三带二
     *      6.顺子
     *      7.两连对(AABB)
     *          71.三连对
     *          72.四连对
     *          73.五连对
     *          74.六连对
     *          75.七连对
     *          76.八连对
     *      8.飞机(AAABBB)
     *          81.三飞机
     *          82.四飞机
     *          83.五飞机
     *     10.炸弹
     */

    //public - 检测扑克牌的牌型是否与上一家打出的牌型相同并且权重大于上一家
    //@param poker 存放牌对象的数组
    //@param surplus 剩余手牌数
    //@param poker_matcing 上家的牌型
    //@param poker_scale 上家牌型的权重
    r.pokerMatcing = function (dataJson, surplus, poker_matcing, poker_scale) {
        var poker_num = Object.keys(dataJson).length;
        var str_poker = '';
        var is_carry; // 带牌是否符合规则
        var return_object = {
            "matcing":0,
            "scale":0,
            "status":0,
        }
        for(var index in dataJson){
            str_poker += dataJson[index].value;//将牌对象转成字符串，用于正则判断
        }
        str_poker = str_poker.replace(/10/g,"S");//由于10占两个字符，对正则匹配有影响，因此批量替换成S
        var result = matcing(str_poker, Object.keys(dataJson).length, dataJson);//判断当前牌型及权重
        return_object.matcing = result[0];
        return_object.scale = result[1];
        // console.log("return_object.matcing : "+return_object.matcing);
        // console.log("return_object.scale : "+return_object.scale);
        //如果没有上家，则只要符合规则都允许出牌。
        if(poker_matcing == 0 && poker_scale == 0){
            return_object.status = 1;
            return return_object;
        }
        //判断牌型是否与上家一致
        if(return_object.matcing != poker_matcing){
            //如果牌型不一致并且为炸弹则直接可以出牌，此处判断可避免上家也是炸弹不判断大小直接出牌
            if(return_object.matcing == 10){
                return_object.status = 1;
            }
            //如果不是炸弹牌型也一致则出牌失败。
            return return_object;
        }

        //判断带牌是否符合
        switch (return_object.matcing){
            // 三不带，三带一
            case 3:
            case 4:
                //剩余手牌数大于0 不允许出牌
                surplus <= 0 ? is_carry = true : is_carry = false;
                break;
            //飞机 双三 需要带 四张 3+3+4 = 10
            case 8:
                if(poker_num == 10){
                    is_carry = true;
                }else{
                    surplus <= 0 ? is_carry = true : is_carry = false;
                }
                break;
            //81.三飞机 3+3+3+6 = 15
            case 81:
                if(poker_num == 15){
                    is_carry = true;
                }else{
                    surplus <= 0 ? is_carry = true : is_carry = false;
                }
                break;
            default:
                is_carry = true;
            //由于牌不够，其余飞机不管带几张都可以出。
        }
        if(is_carry){
            //-------继续判断权重是否大于上家。大于上家则允许出牌
            return_object.status = return_object.scale > poker_scale ? 1 : 0;
        }else{
            return_object.status = 0; //出牌不符合规则。
        }
        return return_object;
    };

    //private - 检测牌型 match返回匹配结果， search返回索引位置
    var matcing = function (poker, poker_num, dataJson) {
        var is_matcing = 0;
        var scale = 0;
        var index = -1;
        switch (poker_num){
            //单张
            case 1:
                is_matcing = 1;
                scale = dataJson[0].scale;
                break;
            //对子 ,牌型类型 2
            case 2:
                poker.match(/(.)\1/) ? is_matcing = 2 : is_matcing = 0;
                scale = dataJson[0].scale;
                break;
            //三张(需最后三张牌才可以出)
            case 3:
                //--AAA
                poker.match(/(.)\1\1/) ? is_matcing = 3 : is_matcing = 0;
                scale = dataJson[0].scale;
                break;
            //炸弹 or 两连对 or 三带一(需最后四张牌才可以出)
            case 4:
                //--AAAA 炸弹判定   10.炸弹
                poker.match(/(.)\1\1\1/) ? is_matcing = 10 : is_matcing = 0;
                if(is_matcing != 0){scale = dataJson[0].scale;break;}
                //--AABB 两连对判定，要判断权重值是否相连 7.连对
                index = poker.search(/(.)\1(.)\2/);
                if(index >= 0){
                    is_scale(dataJson,2,index) ? is_matcing = 7 : is_matcing = 0;
                }
                if(is_matcing != 0){scale = dataJson[index].scale;break;}
                //--4.三带一
                index = -1;  //--重置搜索索引
                index = poker.search(/.*(.)\1\1.*/);
                if(index >= 0){is_matcing = 4;scale = dataJson[index].scale;break;}
                break;
            //三带二
            case 5:
                //5.三带二
                index = poker.search(/.*(.)\1\1.*/);
                if(index >= 0){is_matcing = 5;scale = dataJson[index].scale;break;}
            default :
                //多张牌的情况下，先判断是否为顺子 6.顺子
                shunzi(dataJson) ? is_matcing = 6 : is_matcing = 0;
                if(is_matcing != 0){scale = dataJson[0].scale;break;}

                //-------- 多连对判定 最大连对数 16/2 = 8
                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3(.)\4(.)\5(.)\6(.)\7(.)\8/);//八连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 76 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3(.)\4(.)\5(.)\6(.)\7/);//七连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 75 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3(.)\4(.)\5(.)\6/);//六连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 74 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3(.)\4(.)\5/);//五连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 73 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3(.)\4/);//四连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 72 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1(.)\2(.)\3/);//三连
                if(index >= 0){is_scale(dataJson,2,index) ? is_matcing = 71 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                //--8.飞机判定，最大飞机数 16/3 = 5 //--注：返回具体飞机类型，以判断带几张牌
                index = -1;//初始化为-1
                index = poker.search(/(.)\1\1(.)\2\2(.)\3\3(.)\4\4(.)\5\5/); //五飞83
                if(index >= 0){is_scale_loop(dataJson,3,index,4) ? is_matcing = 83 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1\1(.)\2\2(.)\3\3(.)\4\4/);//四飞82
                if(index >= 0){is_scale_loop(dataJson,3,index,3) ? is_matcing = 82 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1\1(.)\2\2(.)\3\3/);//三飞81
                if(index >= 0){is_scale_loop(dataJson,3,index,2) ? is_matcing = 81 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}

                index = -1;
                index = poker.search(/(.)\1\1(.)\2\2/);//双飞8
                if(index >= 0){is_scale_loop(dataJson,3,index,1) ? is_matcing = 8 : is_matcing = 0;}
                if(is_matcing != 0){scale = dataJson[index].scale;break;}
        }
        var result = [is_matcing, scale];
        return result;
    };
    //private 判断权重是否相连,自定义循环次数
    var is_scale_loop = function (poker_arr, poker_index, poker_start, loop) {
        var scale_ok = true;
        for (var index=poker_start; ; index += poker_index){
            //此处如果权重从大到小排序则是 - 反之是 +
            if((poker_arr[index].scale - 1) != poker_arr[index+poker_index].scale){
                scale_ok = false;
                break;
            }
            //用于控制循环次数
            loop--;
            if(loop<=0){break;}
        }
        return scale_ok;
    }
    //private 判断权重是否相连，通过对象总数来控制循环次数
    var is_scale = function (poker_arr, poker_index, poker_start) {
        var scale_ok = true;
        for (var index=poker_start; ; index += poker_index){
            //如果递增值大于对象总数，则跳出循环避免下标越界
            if(index+poker_index*2>=Object.keys(poker_arr).length){
                break;
            }
            //此处如果权重从大到小排序则是 - 反之是 +
            if((poker_arr[index].scale - 1) != poker_arr[index+poker_index].scale){
                scale_ok = false;
                break;
            }
        }
        return scale_ok;
    }
    //private 判断是否为顺子
    var shunzi = function (poker_arr) {
        var scale_ok = true;
        for (var index=0; index<(Object.keys(poker_arr).length -1); index++){
            //由于2不能当顺子出，检测到二直接跳出循环。
            if(poker_arr[index].scale == 13){
                scale_ok = false;
                break;
            }
            //检测权重是否相连 此处如果权重从大到小排序则是 - 反之是 +
            if(poker_arr[index].scale - 1 != poker_arr[index+1].scale){
                scale_ok = false;
                break;
            }
        }
        return scale_ok;
    }


    window.rule = r;
})(window)
  </script>
</body>
</html>